﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Globalization;
using System.Text.RegularExpressions;

namespace Possan.Localization
{
	public class XmlLibraryProvider : ILibraryProvider
	{
		#region ILibraryProvider Members

		public bool RegisterPhrase(string namespacename, string originalphrase, string translation, System.Globalization.CultureInfo locale)
		{
			return RegisterPhrase(namespacename, originalphrase, translation, locale.Name);

		}

		public bool RegisterPhrase(string namespacename, string originalphrase, string translation, string locale)
		{
			namespacename = namespacename.ToLower();
			if (m_namespaces.ContainsKey(namespacename))
			{
				m_namespaces[namespacename].RegisterPhrase(originalphrase, translation, locale);
			}
			else
			{
				XmlLibraryNamespace newns = new XmlLibraryNamespace(this);
				newns.RegisterPhrase(originalphrase, translation, locale);
				m_namespaces.Add(namespacename, newns);
			}

			return true;
		}

		public bool RegisterPhraseID(string namespacename, string id, string originalphrase, string translation, System.Globalization.CultureInfo locale)
		{
			return RegisterPhraseID(namespacename, id, originalphrase, translation, locale.Name);
		}

		public bool RegisterPhraseID(string namespacename, string id, string originalphrase, string translation, string locale)
		{
			namespacename = namespacename.ToLower();
			if (m_namespaces.ContainsKey(namespacename))
			{
				m_namespaces[namespacename].RegisterPhraseID(id, originalphrase, translation, locale);
			}
			else
			{
				XmlLibraryNamespace newns = new XmlLibraryNamespace(this);
				newns.RegisterPhraseID(id, originalphrase, translation, locale);
				m_namespaces.Add(namespacename, newns);
			}

			return true;
		}

		public string TranslatePhrase(string namespacename, string originalphrase, System.Globalization.CultureInfo locale)
		{
			return TranslatePhrase(namespacename, originalphrase, locale.Name);
		}

		public string TranslatePhrase(string namespacename, string originalphrase, string locale)
		{
			namespacename = namespacename.ToLower();
			string ret = originalphrase;
			if (m_namespaces.ContainsKey(namespacename))
			{
				XmlLibraryNamespace libns = m_namespaces[namespacename];
				ret = libns.GetPhrase(originalphrase, locale);
			}

			return ret;
		}

		public string TranslatePhraseByID(string namespacename, string id, string fallbackphrase, System.Globalization.CultureInfo locale)
		{
			namespacename = namespacename.ToLower();
			string ret = fallbackphrase;
			if (m_namespaces.ContainsKey(namespacename))
			{
				XmlLibraryNamespace libns = m_namespaces[namespacename];
				ret = libns.GetPhraseByID(id, fallbackphrase, locale.Name);
			}
			return ret;
		}

		public void RegisterLocale(string locale)
		{
			CultureInfo ci = new CultureInfo(locale);
			if (!m_locales.Contains(ci))
				m_locales.Add(ci);
		}

		public void DeleteLocale(string locale)
		{
			CultureInfo ci = new CultureInfo(locale);
			if (m_locales.Contains(ci))
				m_locales.Remove(ci);
		}

		public void RegisterNamespace(string namespacename)
		{
			namespacename = namespacename.ToLower();
			if (!m_namespaces.ContainsKey(namespacename))
			{
				XmlLibraryNamespace newns = new XmlLibraryNamespace(this);
				m_namespaces.Add(namespacename, newns);
			}
		}

		public List<string> GetLocales()
		{
			List<string> ret = new List<string>();
			foreach (CultureInfo ci in m_locales)
				ret.Add(ci.Name);
			return ret;
		}

		public List<string> GetNamespaces()
		{
			List<string> ret = new List<string>();

			Dictionary<string, XmlLibraryNamespace>.Enumerator e = m_namespaces.GetEnumerator();
			while (e.MoveNext())
			{
				ret.Add(e.Current.Key);
			}

			return ret;
		}

		public List<string> GetIDs(string namespacename)
		{
			List<string> ret = new List<string>();
			if (!string.IsNullOrEmpty(namespacename))
			{
				if (m_namespaces.ContainsKey(namespacename))
				{
					XmlLibraryNamespace ns = m_namespaces[namespacename];
					if (ns != null)
					{
						ret = ns.GetIDs();
					}
				}
			} 
			return ret;
		}

		public Dictionary<string, string> GetTranslations(string namespacename, string id)
		{
			throw new NotImplementedException();
			Dictionary<string, string> ret = new Dictionary<string, string>();
			return ret;
		}

		#endregion

		public CultureInfo DefaultLocale
		{
			get
			{
				return m_defaultLocale;
			}
			set
			{
				m_defaultLocale = value;
			}
		}

		Dictionary<string, XmlLibraryNamespace> m_namespaces;
		public CultureInfo m_defaultLocale;
		List<CultureInfo> m_locales;

		public XmlLibraryProvider()
		{
			m_namespaces = new Dictionary<string, XmlLibraryNamespace>();
			m_locales = new List<CultureInfo>();// new Dictionary<string, LibraryLocaleInfo>();
			m_defaultLocale = CultureInfo.InvariantCulture;
		}

		public void Clear()
		{
			m_namespaces.Clear();
			m_locales.Clear();
		}

		public static string GenerateID()
		{
			return Regex.Replace(Guid.NewGuid().ToString(), "[^0-9a-z]", "").Substring(0, 6);
		}

		#region Load and save

		public bool ImportXML(Stream s)
		{
			bool ret = false;

			XmlDocument d = new XmlDocument();
			d.Load(s);

			XmlNode transnode = d.SelectSingleNode("translation");
			if (transnode != null)
			{
				if (transnode.Attributes["default"] != null)
				{
					DefaultLocale = CultureInfo.GetCultureInfo(transnode.Attributes["default"].Value);
				}


				XmlNodeList locales = transnode.SelectNodes("locale");
				foreach (XmlNode locale in locales)
				{
					string localename = "";
					if (locale.Attributes["name"] != null)
						localename = locale.Attributes["name"].Value;

					if (localename != "")
					{
						CultureInfo c = new CultureInfo(localename);
						if (!m_locales.Contains(c))
							m_locales.Add(c);
					}
				}

				XmlNodeList namespacenodelist = d.SelectNodes("translation/namespace");
				foreach (XmlNode namespacenode in namespacenodelist)
				{
					string namespacename = "";

					if (namespacenode.Attributes["name"] != null)
						namespacename = namespacenode.Attributes["name"].Value;

					if (namespacename != "")
					{

						XmlNodeList phrases = namespacenode.SelectNodes("phrase");
						foreach (XmlNode phrase in phrases)
						{
							// kolla id

							string phrase_id = "";
							if (phrase.Attributes["id"] != null)
								phrase_id = phrase.Attributes["id"].Value;// idnode.Value.ToString().Trim();
							if (phrase_id == "")
								phrase_id = XmlLibraryProvider.GenerateID();// Regex.Replace(Guid.NewGuid().ToString(), "[^0-9a-z]", "");

							XmlNode originalnode = phrase.SelectSingleNode("orig");
							if (originalnode != null)
							{
								string origphrase = originalnode.InnerText;
								if (m_defaultLocale != null)
									RegisterPhraseID(namespacename, phrase_id, "", origphrase, m_defaultLocale);
							}

							XmlNodeList trannodes = phrase.SelectNodes("tran");
							foreach (XmlNode trannode in trannodes)
							{
								CultureInfo lang = CultureInfo.InvariantCulture;
								string transl = "";
								if (trannode.Attributes["lang"] != null)
									lang = new CultureInfo(trannode.Attributes["lang"].Value);

								transl = trannode.InnerText;

								RegisterPhraseID(namespacename, phrase_id, "", transl, lang);
							}
							// }
						}
					}
				}
			}

			ret = true;

			return ret;
		}

		public bool ExportXML(Stream s)
		{
			bool ret = false;

			XmlDocument d = new XmlDocument();
			{
				d.AppendChild(d.CreateXmlDeclaration("1.0", "UTF-8", "yes"));

				XmlNode transnode = d.CreateElement("translation");
				d.AppendChild(transnode);

				XmlAttribute defaultattr = d.CreateAttribute("default");
				defaultattr.Value = DefaultLocale.Name;
				transnode.Attributes.Append(defaultattr);

				{
					foreach (CultureInfo c in m_locales)
					{
						string localename = c.Name;
						// LibraryLocaleInfo info = le.Current.Value;

						XmlNode pnode = d.CreateElement("locale");

						XmlAttribute nameattr = d.CreateAttribute("name");
						nameattr.Value = localename;
						pnode.Attributes.Append(nameattr);
						/*
						XmlNode notesnode = d.CreateElement("notes");
						notesnode.AppendChild(d.CreateTextNode(info.Notes));
						pnode.AppendChild(notesnode);

						XmlNode contactnode = d.CreateElement("contact");
						contactnode.AppendChild(d.CreateTextNode(info.Contact));
						pnode.AppendChild(contactnode);
						*/
						transnode.AppendChild(pnode);
					}
				}

				Dictionary<string, XmlLibraryNamespace>.Enumerator ne = m_namespaces.GetEnumerator();
				while (ne.MoveNext())
				{
					string namespacename = ne.Current.Key;
					XmlLibraryNamespace nslib = ne.Current.Value;

					XmlNode nsnode = d.CreateElement("namespace");

					XmlAttribute nameattr = d.CreateAttribute("name");
					nameattr.Value = namespacename;
					nsnode.Attributes.Append(nameattr);

					transnode.AppendChild(nsnode);

					nslib.AppendXML(nsnode);

				}
			}

			d.Save(s);
			ret = true;

			return ret;
		}

		public bool ImportXML(string filename)
		{
			bool ret = false;
			if (File.Exists(filename))
			{
				FileStream f = File.Open(filename, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
				if (f != null)
				{
					ret = ImportXML(f);
					f.Close();
				}
			}
			return ret;
		}

		public bool ExportXML(string filename)
		{
			bool ret = false;
			FileStream f = File.Open(filename, FileMode.Create);
			if (f != null)
			{
				ret = ExportXML(f);
				f.Close();
			}
			return ret;
		}

		#endregion

		/*
		public LibraryLocaleInfo GetLocale(string locale)
		{
			return GetLocale(locale, false);
		}

		public LibraryLocaleInfo GetLocale(string locale, bool allowcreate)
		{
			if (locales.ContainsKey(locale))
				return locales[locale];

			if (allowcreate)
			{
				LibraryLocaleInfo info = new LibraryLocaleInfo();
				locales.Add(locale, info);
				return info;
			}

			return null;
		}
		*/

		public int PhraseCount
		{
			get
			{
				int ret = 0;
				Dictionary<string, XmlLibraryNamespace>.Enumerator e1 = m_namespaces.GetEnumerator();
				while (e1.MoveNext())
					ret += e1.Current.Value.PhraseCount;
				return ret;
			}
		}

		public int LocaleCount
		{
			get
			{
				return m_locales.Count;
			}
		}

		public int NamespaceCount
		{
			get
			{
				return m_namespaces.Count;
			}
		}

	}
}
